#include "counter.h"

Counter::Counter(){}

Counter::Counter(QString Dir){
    obj_Dir.setPath(Dir);
    obj_Dir.mkdir("C");
    obj_Dir.cd("C");
    //obj_Dir.setPath(QDir::currentPath().append("/").append(obj_name));

    create_key();
    pvid = new PVID_Authority(Dir);

    // Crea la base de datos que hace la funcion de VoteList(VL)
    if(!QFile::exists(obj_Dir.absoluteFilePath("VoteList").append(".db"))){
        QString cmd("sqlite3 -line ");
        cmd.append(obj_Dir.absoluteFilePath("VoteList")).append(".db ");
        cmd.append("'create table VoteList(PVID BLOB, Ez BLOB, ev BLOB);'");
        system(cmd.toAscii().data());
    }

    // Crea la base de datos que hace la funcion de CounterBulletinBoard(CBB)
    if(!QFile::exists(obj_Dir.absoluteFilePath("CBB").append(".db"))){
        QString cmd("sqlite3 -line ");
        cmd.append(obj_Dir.absoluteFilePath("CBB")).append(".db ");
        cmd.append("'create table CBB(H BLOB);'");
        system(cmd.toAscii().data());
    }

    if(!QSqlDatabase::contains("RLconex"))
        QSqlDatabase::addDatabase("QSQLITE","RLconex");
    if(!QSqlDatabase::contains("Prop_conex"))
        QSqlDatabase::addDatabase("QSQLITE","Prop_conex");
    if(!QSqlDatabase::contains("Moc_conex"))
        QSqlDatabase::addDatabase("QSQLITE","Moc_conex");
    if(!QSqlDatabase::contains("VLconex"))
        QSqlDatabase::addDatabase("QSQLITE","VLconex");
    if(!QSqlDatabase::contains("VKLconex"))
        QSqlDatabase::addDatabase("QSQLITE","VKLconex");
    if(!QSqlDatabase::contains("VLEconex"))
        QSqlDatabase::addDatabase("QSQLITE","VLEconex");
    if(!QSqlDatabase::contains("SLconex"))
        QSqlDatabase::addDatabase("QSQLITE","SLconex");
    if(!QSqlDatabase::contains("BLconex"))
        QSqlDatabase::addDatabase("QSQLITE","BLconex");
    if(!QSqlDatabase::contains("CBBconex"))
        QSqlDatabase::addDatabase("QSQLITE","CBBconex");
    if(!QSqlDatabase::contains("SVLconex"))
        QSqlDatabase::addDatabase("QSQLITE","SVLconex");
}

Counter::Counter(QString Dir, bool no_key){
    obj_Dir.setPath(Dir);
    obj_Dir.mkdir("C");
    obj_Dir.cd("C");
    pvid = new PVID_Authority(Dir);

    if(!QSqlDatabase::contains("RLconex"))
        QSqlDatabase::addDatabase("QSQLITE","RLconex");
    if(!QSqlDatabase::contains("Prop_conex"))
        QSqlDatabase::addDatabase("QSQLITE","Prop_conex");
    if(!QSqlDatabase::contains("Moc_conex"))
        QSqlDatabase::addDatabase("QSQLITE","Moc_conex");
    if(!QSqlDatabase::contains("VLconex"))
        QSqlDatabase::addDatabase("QSQLITE","VLconex");
    if(!QSqlDatabase::contains("VKLconex"))
        QSqlDatabase::addDatabase("QSQLITE","VKLconex");
    if(!QSqlDatabase::contains("VLEconex"))
        QSqlDatabase::addDatabase("QSQLITE","VLEconex");
    if(!QSqlDatabase::contains("SLconex"))
        QSqlDatabase::addDatabase("QSQLITE","SLconex");
    if(!QSqlDatabase::contains("BLconex"))
        QSqlDatabase::addDatabase("QSQLITE","BLconex");
    if(!QSqlDatabase::contains("CBBconex"))
        QSqlDatabase::addDatabase("QSQLITE","CBBconex");
    if(!QSqlDatabase::contains("SVLconex"))
        QSqlDatabase::addDatabase("QSQLITE","SVLconex");
}

Counter::~Counter(){}

void Counter::ResumenResultadosProp(QString dir_propuestas,QString desc,QString &str_opciones,QString &num_opciones){
    QStringList opciones;
    QString buffer;
    int num[]={0,0,0,0,0};
    int size;

    // Crea la conexion a la VotesList
    QSqlDatabase RL = QSqlDatabase::database("RLconex",false);
    RL.setDatabaseName(obj_Dir.absoluteFilePath("ResultList.db"));
    if(!RL.open()){
        return;
    }

    QSqlTableModel RLmodel(0,RL);
    RLmodel.setTable("ResultList");
    RLmodel.setEditStrategy(QSqlTableModel::OnManualSubmit);
    RLmodel.select();

// Manipulacion del string desc para separar el numero de propuesta y de subpropuesta
    QString num_prop,sub_prop;
    int num_size,sub_size;

    desc.remove(0,10);

    num_size = desc.indexOf("-");
    sub_size = desc.indexOf(":");

    if(num_size==-1 || num_size>sub_size){
        for(int j=0;j<sub_size; j++){
            num_prop.append(desc.at(j));
        }
    }
    else if(num_size<sub_size){
            for(int j=0;j<num_size; j++){
                num_prop.append(desc.at(j));
            }
            desc.remove(0,num_size+1);
            sub_size = desc.indexOf(":");
            for(int g=0;g<sub_size; g++){
                sub_prop.append(desc.at(g));
            }
    }

    // Crea la conexion a la base de datos de las propuestas
    QSqlDatabase prop = QSqlDatabase::database("Prop_conex",false);
    prop.setDatabaseName(dir_propuestas);
    if(!prop.open()){
        return;
    }

    QSqlTableModel Propmodel(0,prop);
    Propmodel.setTable("propuestas");
    Propmodel.setEditStrategy(QSqlTableModel::OnManualSubmit);
    if(sub_prop.isEmpty())
        Propmodel.setFilter(QString("num_prop= ").append(num_prop));
    else
        Propmodel.setFilter(QString("num_prop= ").append(num_prop).append(" and sub_prop='").append(sub_prop).append("'"));
    Propmodel.select();

    switch(Propmodel.record(0).value("tipo_voto").toInt()){
    case 1:{
        opciones << "A favor"<<"En contra";
        size = 2;
        break;}
    case 2:
        opciones << Propmodel.record(0).value("opc1_desc").toString();
        opciones << Propmodel.record(0).value("opc2_desc").toString();
        size = 2;
        break;
    case 3:
        opciones << Propmodel.record(0).value("opc1_desc").toString();
        opciones << Propmodel.record(0).value("opc2_desc").toString();
        opciones << Propmodel.record(0).value("opc3_desc").toString();
        size = 3;
        break;
    case 4:
        opciones << Propmodel.record(0).value("opc1_desc").toString();
        opciones << Propmodel.record(0).value("opc2_desc").toString();
        opciones << Propmodel.record(0).value("opc3_desc").toString();
        opciones << Propmodel.record(0).value("opc4_desc").toString();
        size = 4;
        break;
    case 5:
        opciones << Propmodel.record(0).value("opc1_desc").toString();
        opciones << Propmodel.record(0).value("opc2_desc").toString();
        opciones << Propmodel.record(0).value("opc3_desc").toString();
        opciones << Propmodel.record(0).value("opc4_desc").toString();
        opciones << Propmodel.record(0).value("opc5_desc").toString();
        size = 5;
        break;
    }


    for(int i=0;i<RLmodel.rowCount();i++){
        buffer=RLmodel.record(i).value("B").toString();
        for(int t=0;t<4;t++){
            shift_String(buffer);}
        for(int t=1;t<=RLmodel.record(i).value("Vp").toInt();t++){
            if(t!=RLmodel.record(i).value("Vp").toInt()){
                shift_String(buffer);
            }else{
                QString ui(shift_String(buffer));
                int ry =opciones.indexOf(ui);
                num[ry]++;
            }
        }
    }
    int total = 0;
    for(int g=0;g<size;g++){
        str_opciones.append(opciones.at(g));
        str_opciones.append("&&");

        num_opciones.append(QString::number(num[g]));
        num_opciones.append("&&");
        total = total + num[g];
        }
    total+=unVoted();
    num_opciones.append(QString::number(unVoted())).append("&&");
    num_opciones.append(QString::number(total));
}

void Counter::ResumenResultadosMoc(QString dir_mociones,QString desc,QString &str_opciones,QString &num_opciones){
    QStringList opciones;
    QString buffer;
    int num[]={0,0,0,0,0};
    int size;

    // Crea la conexion a la VotesList
    QSqlDatabase RL = QSqlDatabase::database("RLconex",false);
    RL.setDatabaseName(obj_Dir.absoluteFilePath("ResultList.db"));
    if(!RL.open()){
        return;
    }

    QSqlTableModel RLmodel(0,RL);
    RLmodel.setTable("ResultList");
    RLmodel.setEditStrategy(QSqlTableModel::OnManualSubmit);
    RLmodel.select();

// Manipulacion del string desc para separar el numero de propuesta y de subpropuesta
    QString num_prop,sub_prop;
    int num_size,sub_size;

    desc.remove(0,7);

    num_size = desc.indexOf("-");
    sub_size = desc.indexOf(":");

    if(num_size==-1 || num_size>sub_size){
        for(int j=0;j<sub_size; j++){
            num_prop.append(desc.at(j));
        }
    }
    else if(num_size<sub_size){
            for(int j=0;j<num_size; j++){
                num_prop.append(desc.at(j));
            }
            desc.remove(0,num_size+1);
            sub_size = desc.indexOf(":");
            for(int g=0;g<sub_size; g++){
                sub_prop.append(desc.at(g));
            }
    }

    // Crea la conexion a la base de datos de las mociones
    QSqlDatabase prop = QSqlDatabase::database("Moc_conex",false);
    prop.setDatabaseName(dir_mociones);
    if(!prop.open()){
        return;
    }

    QSqlTableModel Propmodel(0,prop);
    Propmodel.setTable("mociones");
    Propmodel.setEditStrategy(QSqlTableModel::OnManualSubmit);
    if(sub_prop.isEmpty())
        Propmodel.setFilter(QString("num_moc= ").append(num_prop));
    else
        Propmodel.setFilter(QString("num_moc= ").append(num_prop).append(" and sub_moc='").append(sub_prop).append("'"));
    Propmodel.select();
    int rpor = Propmodel.rowCount();

    switch(Propmodel.record(0).value("tipo_voto").toInt()){
    case 1:{
        opciones << "A favor"<<"En contra";
        size = 2;
        break;}
    case 2:
        opciones << Propmodel.record(0).value("opc1_desc").toString();
        opciones << Propmodel.record(0).value("opc2_desc").toString();
        size = 2;
        break;
    case 3:
        opciones << Propmodel.record(0).value("opc1_desc").toString();
        opciones << Propmodel.record(0).value("opc2_desc").toString();
        opciones << Propmodel.record(0).value("opc3_desc").toString();
        size = 3;
        break;
    case 4:
        opciones << Propmodel.record(0).value("opc1_desc").toString();
        opciones << Propmodel.record(0).value("opc2_desc").toString();
        opciones << Propmodel.record(0).value("opc3_desc").toString();
        opciones << Propmodel.record(0).value("opc4_desc").toString();
        size = 4;
        break;
    case 5:
        opciones << Propmodel.record(0).value("opc1_desc").toString();
        opciones << Propmodel.record(0).value("opc2_desc").toString();
        opciones << Propmodel.record(0).value("opc3_desc").toString();
        opciones << Propmodel.record(0).value("opc4_desc").toString();
        opciones << Propmodel.record(0).value("opc5_desc").toString();
        size = 5;
        break;
    }


    for(int i=0;i<RLmodel.rowCount();i++){
        buffer=RLmodel.record(i).value("B").toString();
        for(int t=0;t<4;t++){
            shift_String(buffer);}
        for(int t=1;t<=RLmodel.record(i).value("Vp").toInt();t++){
            if(t!=RLmodel.record(i).value("Vp").toInt()){
                shift_String(buffer);
            }else{
                QString ui(shift_String(buffer));
                int ry =opciones.indexOf(ui);
                num[ry]++;
            }
        }
    }

    int total = 0;
    for(int g=0;g<size;g++){
        str_opciones.append(opciones.at(g));
        str_opciones.append("&&");

        num_opciones.append(QString::number(num[g]));
        num_opciones.append("&&");
        total = total + num[g];
        }

    total+=unVoted();
    num_opciones.append(QString::number(unVoted())).append("&&");
    num_opciones.append(QString::number(total));
}

void Counter::Matching_dz(QString dir_2_dz){
    {
    // Crea la conexion a la VoteList
        QSqlDatabase VL = QSqlDatabase::database("VLconex",false);
        VL.setDatabaseName(obj_Dir.absoluteFilePath("VoteList.db"));
        if(!VL.open()){
            return;
        }

        QSqlTableModel VLmodel(0,VL);
        VLmodel.setTable("VoteList");
        VLmodel.setEditStrategy(QSqlTableModel::OnManualSubmit);
        VLmodel.select();

    // Crea la conexion a la VotingKeyList
        QSqlDatabase VKL = QSqlDatabase::database("VKLconex",false);
        VKL.setDatabaseName(dir_2_dz);
        if(!VKL.open()){
            return;
        }

        QSqlTableModel VKLmodel(0,VKL);
        VKLmodel.setTable("VotingKeyList");
        VKLmodel.setEditStrategy(QSqlTableModel::OnManualSubmit);
        VKLmodel.select();

    // Crea una base de datos con (PVID1,Ez,ev,dz)

        if(QFile::exists(obj_Dir.absoluteFilePath("VoteListExtended.db"))){
            QFile::remove(obj_Dir.absoluteFilePath("VoteListExtended.db"));
        }

        QString cmd("sqlite3 ");
        cmd.append(obj_Dir.absoluteFilePath("VoteListExtended.db "));
        cmd.append("'create table VoteListExtended(PVID BLOB, Ez BLOB, ev BLOB, dz BLOB);'");
        system(cmd.toAscii().data());

    // Crea la conexion a la VoteListExtended
        QSqlDatabase VLE = QSqlDatabase::database("VLEconex",false);
        VLE.setDatabaseName(obj_Dir.absoluteFilePath("VoteListExtended.db"));
        if(!VLE.open()){
            return;
        }

        QSqlTableModel VLEmodel(0,VLE);
        VLEmodel.setTable("VoteListExtended");
        VLEmodel.setEditStrategy(QSqlTableModel::OnManualSubmit);
        VLEmodel.select();

        for(int i=0;i<VLmodel.rowCount();i++){

            int row = 0;
            VLEmodel.insertRows(row, 1);
            VKLmodel.setFilter(QString("ev='").append(VLmodel.record(i).value("ev").toString()).append("'"));
            VLEmodel.setData(VLEmodel.index(row, VLEmodel.fieldIndex("PVID")),VLmodel.record(i).value("PVID"));
            VLEmodel.setData(VLEmodel.index(row, VLEmodel.fieldIndex("Ez")),VLmodel.record(i).value("Ez"));
            VLEmodel.setData(VLEmodel.index(row, VLEmodel.fieldIndex("ev")),VLmodel.record(i).value("ev"));
            VLEmodel.setData(VLEmodel.index(row, VLEmodel.fieldIndex("dz")),VKLmodel.record(0).value("dz"));
            VLEmodel.submitAll();
        }
    }
}

void Counter::SimplifiedList(){
    {
        QString Ez,PVID2,Vp;
        int Vp_size;
    // Crea una base de datos con (PVID1,PVID2,Vp)

        if(QFile::exists(obj_Dir.absoluteFilePath("SimplifiedList.db"))){
            QFile::remove(obj_Dir.absoluteFilePath("SimplifiedList.db"));
        }

        QString cmd("sqlite3 ");
        cmd.append(obj_Dir.absoluteFilePath("SimplifiedList.db "));
        cmd.append("'create table SimplifiedList(PVID1 BLOB, PVID2 BLOB, Vp BLOB);'");
        system(cmd.toAscii().data());

    // Crea la conexion a la SimplifiedList
        QSqlDatabase SL = QSqlDatabase::database("SLconex",false);
        SL.setDatabaseName(obj_Dir.absoluteFilePath("SimplifiedList.db"));
        if(!SL.open()){
            return;
        }

        QSqlTableModel SLmodel(0,SL);
        SLmodel.setTable("SimplifiedList");
        SLmodel.setEditStrategy(QSqlTableModel::OnManualSubmit);
        SLmodel.select();

    // Crea la conexion a la VoteListExtended
        QSqlDatabase VLE = QSqlDatabase::database("VLEconex",false);
        VLE.setDatabaseName(obj_Dir.absoluteFilePath("VoteListExtended.db"));
        if(!VLE.open()){
            return;
        }

        QSqlTableModel VLEmodel(0,VLE);
        VLEmodel.setTable("VoteListExtended");
        VLEmodel.setEditStrategy(QSqlTableModel::OnManualSubmit);
        VLEmodel.select();

        for(int i=0;i<VLEmodel.rowCount();i++){
            Hex2Key(VLEmodel.record(i).value("dz").toString(),"dz");
            Ez=VLEmodel.record(i).value("Ez").toString();
            decryptMsg("dz",Ez,PVID2);
            Vp_size=shift_String(PVID2).toInt();
            Vp=shift_String(PVID2,Vp_size);

            //// Chequear el PVID2, si falla, descarta el mensaje
            if(!pvid->PVID_verification(PVID2,"PVID2")){
                return;
            }


            int row = 0;
            SLmodel.insertRows(row, 1);
            SLmodel.setData(SLmodel.index(row,SLmodel.fieldIndex("PVID1")),VLEmodel.record(i).value("PVID"));
            SLmodel.setData(SLmodel.index(row,SLmodel.fieldIndex("Vp")),shift_String(Vp,Vp_size));
            SLmodel.setData(SLmodel.index(row,SLmodel.fieldIndex("PVID2")),Vp);
            SLmodel.submitAll();

        }
    }
}

void Counter::ResultsList(QString dir_2_B){
        {
        // Crea la conexion a la SimplifiedList
            QSqlDatabase SL = QSqlDatabase::database("SLconex",false);
            SL.setDatabaseName(obj_Dir.absoluteFilePath("SimplifiedList.db"));
            if(!SL.open()){
                return;
            }

            QSqlTableModel SLmodel(0,SL);
            SLmodel.setTable("SimplifiedList");
            SLmodel.setEditStrategy(QSqlTableModel::OnManualSubmit);
            SLmodel.select();

        // Crea la conexion a la BallotList
            QSqlDatabase BL = QSqlDatabase::database("BLconex",false);
            BL.setDatabaseName(dir_2_B);
            if(!BL.open()){
                return;
            }

            QSqlTableModel BLmodel(0,BL);
            BLmodel.setTable("BallotList");
            BLmodel.setEditStrategy(QSqlTableModel::OnManualSubmit);
            BLmodel.select();

        // Crea una base de datos con (PVID1,PVID2,Vp,B)

            if(QFile::exists(obj_Dir.absoluteFilePath("ResultList.db"))){
                QFile::remove(obj_Dir.absoluteFilePath("ResultList.db"));
            }

            QString cmd("sqlite3 ");
            cmd.append(obj_Dir.absoluteFilePath("ResultList.db "));
            cmd.append("'create table ResultList(PVID1 BLOB, PVID2 BLOB, Vp BLOB, B BLOB);'");
            system(cmd.toAscii().data());

        // Crea la conexion a la VotesList
            QSqlDatabase RL = QSqlDatabase::database("RLconex",false);
            RL.setDatabaseName(obj_Dir.absoluteFilePath("ResultList.db"));
            if(!RL.open()){
                return;
            }

            QSqlTableModel RLmodel(0,RL);
            RLmodel.setTable("ResultList");
            RLmodel.setEditStrategy(QSqlTableModel::OnManualSubmit);
            RLmodel.select();

            for(int i=0;i<SLmodel.rowCount();i++){

                int row = 0;
                RLmodel.insertRows(row, 1);
                BLmodel.setFilter(QString("PVID='").append(SLmodel.record(i).value("PVID1").toString()).append("'"));

                RLmodel.setData(RLmodel.index(row, RLmodel.fieldIndex("PVID1")),SLmodel.record(i).value("PVID1"));
                RLmodel.setData(RLmodel.index(row, RLmodel.fieldIndex("PVID2")),SLmodel.record(i).value("PVID2"));
                RLmodel.setData(RLmodel.index(row, RLmodel.fieldIndex("Vp")),SLmodel.record(i).value("Vp"));
                RLmodel.setData(RLmodel.index(row, RLmodel.fieldIndex("B")),BLmodel.record(0).value("B"));
                RLmodel.submitAll();
            }
        }
}

void Counter::SubVoteList(){
// Crea la conexion
    QSqlDatabase VL = QSqlDatabase::database("VLconex",false);
    VL.setDatabaseName(obj_Dir.absoluteFilePath("VoteList.db"));
    if(!VL.open()){
        return;
    }

// Crea el modelo
    QSqlTableModel VLmodel(0,VL);
    VLmodel.setTable("VoteList");
    VLmodel.setEditStrategy(QSqlTableModel::OnManualSubmit);
    VLmodel.select();

// Crea la base de datos que hace la funcion de SubVoteList
    if(QFile::exists(obj_Dir.absoluteFilePath("SubVoteList").append(".db"))){
        QFile::remove(obj_Dir.absoluteFilePath("SubVoteList.db"));
    }
    QString cmd("sqlite3 -line ");
    cmd.append(obj_Dir.absoluteFilePath("SubVoteList.db "));
    cmd.append("'create table SubVoteList(Ez BLOB);'");
    system(cmd.toAscii().data());


    QSqlDatabase SVL = QSqlDatabase::database("SVLconex",false);
    SVL.setDatabaseName(obj_Dir.absoluteFilePath("SubVoteList.db"));
    if(!SVL.open()){
        return;
    }

// Crea el modelo
    QSqlTableModel SVLmodel(0,SVL);
    SVLmodel.setTable("SubVoteList");
    SVLmodel.setEditStrategy(QSqlTableModel::OnManualSubmit);
    SVLmodel.select();

    for(int i = 0;i<VLmodel.rowCount();i++){
        SVLmodel.insertRows(0,1);
        SVLmodel.setData(SVLmodel.index(0,SVLmodel.fieldIndex("Ez")),VLmodel.record(i).value("Ez"));
        SVLmodel.submitAll();
    }

}

void Counter::create_key(){
    QString namePubKey="ec";
    QString namePriKey="dc";

    InvertibleRSAFunction params;
    params.GenerateRandomWithKeySize( rng, 1024);
    RSA::PrivateKey pri( params );

    RSA::PublicKey pub(pri);

    SavePublicKey(namePubKey,pub);
    SavePrivateKey(namePriKey,pri);
}

bool Counter::M6(QString &m6){
    QString Ec,PVID1,Ez,ev;
    int PVID1_size,Ez_size;

// Decripta M6 y divide su contenido
    if(!decryptMsg("dc",m6,Ec)){
        return false;
    }

// Divide el contenido de M6
    PVID1_size = shift_String(Ec).toInt();
    Ez_size = shift_String(Ec).toInt();

    PVID1 = shift_String(Ec,PVID1_size);
    Ez = shift_String(Ec,Ez_size);
    ev = Ec;

// Verifica el PVID
    if(!pvid->PVID_verification(PVID1,"PVID1")){
        return false;
    }

// Crea el hash de Ez y lo publica en el CBB
    if(!Save_Hash(Ez)){
        return false;
    }

// Se guarda la informacion en el VoteList (PVID1, Ěz(V', PVID2), ev)
    if(!Save_in_VL(PVID1,Ez,ev)){
        return false;
    }

    pvid->set_voted(PVID1);
    return true;
}

bool Counter::Save_in_VL(QString PVID, QString Ez, QString ev){
/*  Crear la conexion con la base de datos
    Crear el modelo que manipule la base de datos

    Copiar los datos en la base de datos
  */

    {
        // Crea la conexion
        QSqlDatabase VL = QSqlDatabase::database("VLconex",false);
        VL.setDatabaseName(obj_Dir.absoluteFilePath("VoteList.db"));

        if(!VL.open()){
            return false;
        }

        // Crea el modelo
        QSqlTableModel VLmodel(0,VL);
        VLmodel.setTable("VoteList");
        VLmodel.setEditStrategy(QSqlTableModel::OnManualSubmit);
        VLmodel.select();

        // Copia las llaves en la base de datos
        int row = 0;
        VLmodel.insertRows(row, 1);
        VLmodel.setData(VLmodel.index(row, VLmodel.fieldIndex("PVID")),PVID);
        VLmodel.setData(VLmodel.index(row, VLmodel.fieldIndex("Ez")),Ez);
        VLmodel.setData(VLmodel.index(row, VLmodel.fieldIndex("ev")),ev);
        VLmodel.submitAll();
    }
    return true;
}

bool Counter::Save_Hash(QString Ez){
/*  Crear la conexion con la base de datos
    Crear el modelo que manipule la base de datos
    Crear el hash H(B,es)
    Copiar el hash en la base de datos
  */
    {
    // Crea la conexion
        QSqlDatabase CBB = QSqlDatabase::database("CBBconex",false);
        CBB.setDatabaseName(obj_Dir.absoluteFilePath("CBB.db"));

        if(!CBB.open()){
            return false;
        }

    // Crea el modelo
        QSqlTableModel CBBmodel(0,CBB);
        CBBmodel.setTable("CBB");
        CBBmodel.setEditStrategy(QSqlTableModel::OnManualSubmit);
        CBBmodel.select();

    // Crea el hash
        QString H = Hash(Ez);

    // Copia el Hash en la base de datos
        int row = 0;
        CBBmodel.insertRows(row, 1);
        CBBmodel.setData(CBBmodel.index(row, CBBmodel.fieldIndex("H")),H);
        CBBmodel.submitAll();
    }
    return true;
}

QString Counter::Hash(QString H){
// Genera la funcion hash de las llaves key1 y key2
    SHA sha;
    string output;

    sha.Update((byte const*)H.toAscii().data(), H.size());

    SecByteBlock sbbDigest(sha.DigestSize());

    sha.Final(sbbDigest.begin());
    HexEncoder enc(new StringSink(output));
    enc.Put(sbbDigest.begin(), sbbDigest.size());
    enc.MessageEnd();

    return QString::fromStdString(output);
}

void Counter::SavePrivateKey(QString &filename, const PrivateKey &key){
    ByteQueue queue;
    key.Save(queue);

    Save(filename, queue);
}

void Counter::SavePublicKey(QString &filename, const PublicKey &key){
    ByteQueue queue;
    key.Save(queue);

    Save(filename, queue);
}

void Counter::Save(QString &filename, const BufferedTransformation &bt){
    filename.prepend("/");
    filename.prepend(obj_Dir.absolutePath());

    FileSink file(filename.toAscii().data());

    bt.CopyTo(file);
    file.MessageEnd();
}

void Counter::LoadPublicKey(QString filename, PublicKey &key){
    // http://www.cryptopp.com/docs/ref/class_byte_queue.html
    ByteQueue queue;
    Load(filename, queue);
    key.Load(queue);
}

void Counter::LoadPrivateKey(QString filename, PrivateKey &key){
    // http://www.cryptopp.com/docs/ref/class_byte_queue.html
    ByteQueue queue;
    Load(filename, queue);

    key.Load(queue);
}

void Counter::Load(QString filename, BufferedTransformation& bt)
{
    // http://www.cryptopp.com/docs/ref/class_file_source.html
    filename.prepend("/");
    filename.prepend(obj_Dir.absolutePath());

    FileSource file(filename.toAscii().data(), true /*pumpAll*/);
    file.TransferTo(bt);

    bt.MessageEnd();

}

bool Counter::Hex2Key(QString keydata, QString keyname){
    QFile file(obj_Dir.absoluteFilePath(keyname));
    if(!file.open(QIODevice::WriteOnly)){
        return false;}

//    QByteArray BA = file.readAll();

    string decodedKey;

    HexDecoder deco(new StringSink(decodedKey));
    deco.Put((byte*)keydata.toStdString().data(),keydata.size());
    deco.MessageEnd();

    file.write(decodedKey.data(),decodedKey.size());

    file.close();
    return true;
}

bool Counter::Key2Hex(QString keyname, QString &keyHex){
    QFile file(obj_Dir.absoluteFilePath(keyname));
    if(!file.open(QIODevice::ReadOnly)){
        return false;}

    QByteArray BA = file.readAll();

    string encodedKey;

    HexEncoder hex(new StringSink(encodedKey));
    hex.Put((const byte*)BA.data(),BA.size());
    hex.MessageEnd();

    keyHex=QString::fromStdString(encodedKey);

    return true;
}

QString Counter::encryptMsg(QString Data,QString keyName){
    QString out;
    string plainMsg,encryptedMsg,buf;

//Convierto de QString a std::string
//En estos métodos es importantísimo porque si se usa QString directamente, corta el mensaje y despues no se puede desencriptar
    plainMsg=Data.toStdString();

    RSA::PublicKey pub;

    LoadPublicKey(keyName,pub);

    RSAES_OAEP_SHA_Encryptor e( pub);

    while(plainMsg.size()>0){
        buf.clear();
        if(plainMsg.size()<=86){
            buf=plainMsg;
            plainMsg.clear();

        }
        else{
            for(int j=0;j<86; j++){
                buf+=plainMsg.at(j);
            }
            plainMsg.erase(0,86);
        }

        StringSource(buf, true,
            new PK_EncryptorFilter( rng, e,
                new StringSink( encryptedMsg )
            ) // PK_EncryptorFilter
         ); // StringSource
    }

    return QString::fromStdString(encryptedMsg);
}

bool Counter::decryptMsg(QString key2use,QString &Data,QString &decryptedMsg){
    string decrypted_Msg,buf;
    RSA::PrivateKey pri;

    LoadPrivateKey(key2use.toAscii().data(),pri);

    RSAES_OAEP_SHA_Decryptor d( pri );

    //Convierto de QString a std::string
    //En estos métodos es importantísimo porque si se usa QString directamente, corta el mensaje y no se puede desencriptar
    try{
        while(Data.size()>0){
            buf=QString(shift_String(Data,128)).toStdString();

            StringSource(buf, true,
                new PK_DecryptorFilter( rng, d,
                    new StringSink( decrypted_Msg )
                ) // PK_DecryptorFilter
             ); // StringSource

        }
    }
    catch(...){
        return false;
    }
    decryptedMsg = QString::fromStdString(decrypted_Msg);
    return true;
}

QString Counter::shift_String(QString &msg){
    QString buffer;

    int shift = msg.indexOf("&&");

    for(int j=0;j<shift; j++){
        buffer.append(msg.at(j));
    }

    msg.remove(0,shift);
    msg.remove(0,2); // borra &&
    return buffer;
}

QString Counter::shift_String(QString &msg,int max){
    QString buffer;

    for(int j=0;j<max; j++){
        buffer.append(msg.at(j));
    }

    msg.remove(0,max);
    return buffer;
}

int Counter::unVoted(){
    int total,Voted;
    QSqlDatabase PVID_List = QSqlDatabase::database("PVIDconex",false);
    QDir PVID_Dir(obj_Dir);
    PVID_Dir.cdUp();
    PVID_List.setDatabaseName(PVID_Dir.absoluteFilePath("PVID_List.db"));
    bool rt = PVID_List.open();

// Crea el modelo
    QSqlTableModel *PVIDmodel = new QSqlTableModel(0,PVID_List);
    PVIDmodel->setTable("list");
    PVIDmodel->setEditStrategy(QSqlTableModel::OnManualSubmit);
    PVIDmodel->setSort(1,Qt::AscendingOrder);
    PVIDmodel->select();

    total = PVIDmodel->rowCount();

    PVIDmodel->setFilter("vote_saved='si'");
    PVIDmodel->select();

    Voted = PVIDmodel->rowCount();

    return (total-Voted);

}
